#include "stdafx.h"

#include "input/mouse.h"
#include "core/event.h"
#include "core/logger.h"

namespace natrium {
	namespace input {
		Mouse::Mouse() {
			core::EventChannel chan;

			chan.add<MouseMoved>(this);
		
			chan.add<MouseLeftButtonPressed>(this);
			chan.add<MouseMiddleButtonPressed>(this);
			chan.add<MouseRightButtonPressed>(this);
		
			chan.add<MouseLeftButtonPressed>(this);
			chan.add<MouseMiddleButtonPressed>(this);
			chan.add<MouseRightButtonPressed>(this);

			chan.add<MouseWheel>(this);

			for (auto& button: mButtonPressed)
				button = false;

			mWheel = 0;
		}

		Mouse::~Mouse() {
		}

		void Mouse::glfwMousePosCallback(int x, int y) {
			static core::EventChannel chan;
			chan.broadcast(MouseMoved(x, y));
		}

		void Mouse::glfwMouseButtonCallback(int button, int state) {
			static core::EventChannel chan;
		
			switch (button) {
			case GLFW_MOUSE_BUTTON_LEFT:
				switch (state) {
				case GLFW_PRESS:
					chan.broadcast(MouseLeftButtonPressed());
					break;

				case GLFW_RELEASE:
					chan.broadcast(MouseLeftButtonReleased());
					break;

				default:
					gLog << "Mouse: unhandled button state: " << state;
					break;
				}
				break;

			case GLFW_MOUSE_BUTTON_MIDDLE:
				switch (state) {
				case GLFW_PRESS:
					chan.broadcast(MouseMiddleButtonPressed());
					break;

				case GLFW_RELEASE:
					chan.broadcast(MouseMiddleButtonReleased());
					break;

				default:
					gLog << "Mouse: unhandled button state: " << state;
					break;
				}
				break;

			case GLFW_MOUSE_BUTTON_RIGHT:
				switch (state) {
				case GLFW_PRESS:
					chan.broadcast(MouseRightButtonPressed());
					break;

				case GLFW_RELEASE:
					chan.broadcast(MouseRightButtonReleased());
					break;

				default:
					gLog << "Mouse: unhandled button state: " << state;
					break;
				}
				break;

			default:
				gLog << "Mouse: unhandled button type: " << button;
			}
		}

		void Mouse::glfwMouseWheelCallback(int value) {
			static core::EventChannel chan;
			chan.broadcast(MouseWheel(value));
		}

		Mouse::MouseMoved::MouseMoved(int x, int y):
			mX(x), 
			mY(y)
		{
		}

		Mouse::MouseWheel::MouseWheel(int value):
			mValue(value)
		{
		}

		void Mouse::operator()(const MouseMoved& mm) {
			mX = mm.mX;
			mY = mm.mY;
		}

		void Mouse::operator()(const MouseLeftButtonPressed& ) {
			mButtonPressed[LEFT_BUTTON] = true;
		}

		void Mouse::operator()(const MouseMiddleButtonPressed& ) {
			mButtonPressed[MIDDLE_BUTTON] = true;
		}

		void Mouse::operator()(const MouseRightButtonPressed& ) {
			mButtonPressed[RIGHT_BUTTON] = true;
		}

		void Mouse::operator()(const MouseLeftButtonReleased& ) {
			mButtonPressed[LEFT_BUTTON] = false;
		}

		void Mouse::operator()(const MouseMiddleButtonReleased& ) {
			mButtonPressed[MIDDLE_BUTTON] = false;
		}

		void Mouse::operator()(const MouseRightButtonReleased& ) {
			mButtonPressed[RIGHT_BUTTON] = false;
		}

		void Mouse::operator()(const MouseWheel& mw) {
			mWheel = mw.mValue;
		}
	}
}